﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Windows.Media.Imaging;
using AppTouchScreen.Data;
using AppTouchScreen.Imaging;

namespace AppTouchScreen.Model
{
    /// <summary>
    /// Represents a cover for display in a view
    /// </summary>
    public class DisplayCover : INotifyPropertyChanged
    {
        /// <summary>
        /// Encapsulated data (StoreElement)
        /// </summary>
        private readonly StoreElement _source = null;

        #region Constructors 

        private DisplayCover(){}

        public DisplayCover(StoreElement source)
        {
            if (source != null)
            {
                _source = source;
            }
            else
            {
                throw new Exception("source Cannot be null");
            }
        }

        #endregion //Constructors

        #region Data

        public string Name
        {
            get { return _source.Name; }
            set
            {
                _source.Name = value;
                OnPropertyChanged(() => Name);
            }
        }

        public string Description
        {
            get { return _source.Description; }
            set
            {
                _source.Description = value;
                OnPropertyChanged(() => Description);

            }
        }

        public string Price
        {
            get
            {
                if ((IsProduct) && (_source != null))
                {
                    return (_source as Product).Price;
                }
                else
                {
                    return "";
                }
            }
            set
            {
                if ((IsProduct) && (_source != null))
                {
                    (_source as Product).Price = value;
                    OnPropertyChanged(() => Price);
                }
            }
        }

        public ImageInfo Picture
        {
            get { return _source.Image; }
            set
            {
                if (value != null)
                {
                    _source.Image = value;
                    OnPropertyChanged(() => Picture);
                }
            }
        }

        #endregion //Data

        #region Read-only properties

        public bool IsCategory
        {
            get { return _source is Category; }
        }

        public bool IsProduct
        {
            get { return _source is Product; }
        }

        /// <summary>
        /// Encapsulated data (StoreElement)
        /// </summary>
        public StoreElement Source
        {
            get { return _source; }
        }

        public DisplayCover Root
        {
            get
            {
                Category root;
                if (_source is Category)
                {
                    root = _source as Category;
                }
                else
                {
                    root = _source.Parent;
                }

                while (root.Parent != null)
                {
                    //this.Picture.StreamSource
                    root = root.Parent;
                }

                return new DisplayCover(root);
            }
        }

        public ObservableCollection<DisplayCover> Children
        {
            get
            {
                ObservableCollection<DisplayCover> children = null;
                if (IsProduct)
                {
                    return null;
                }
                else if (IsCategory)
                {
                    var category = _source as Category;
                    children = new ObservableCollection<DisplayCover>();
                    if (category.Children != null)
                    {
                        foreach (var element in category.Children)
                        {
                            children.Add(new DisplayCover(element));
                        }
                    }
                }
                else
                {
                    throw new Exception("Uncnoun type");
                }
                return children;
            }
        }

        public DisplayCover Parent
        {
            get
            {
                if (_source.Parent != null)
                {
                    return new DisplayCover(_source.Parent);
                }
                else
                {
                    return null;
                }

            }
        }

        /// <summary>
        /// Depth of datat tree 
        /// </summary>
        public ObservableCollection<DisplayCover> Depth
        {
            get
            {
                var depth = new ObservableCollection<DisplayCover>();


                Category cat = null;
                if (IsCategory)
                {
                    cat = _source as Category;
                }
                else if (IsProduct)
                {
                    cat = _source.Parent;
                }
                else
                {
                    throw new Exception("Uncnoun type. Must be Category or Product");
                }

                while (cat != null)
                {
                    depth.Insert(0, new DisplayCover(cat));
                    cat = cat.Parent;
                }
                //depth.Insert(0, new DisplayCover(cat));

                return depth;

                //var pProduct = new ObservableCollection<CustomAppElement>();
                //Category cat = category;
                //while (cat != null)
                //{
                //    pProduct.Insert(0, cat);
                //    cat = cat.Parent;
                //}
                //return pProduct;
            }
        }

        #endregion //Read-only properties

        #region Methods

        /// <summary>
        /// Create new product and add to this as children
        /// </summary>
        /// <returns></returns>
        public DisplayCover AddProduct()
        {
            if (IsCategory)
            {
                var p = new Product(_source as Category);
                return new DisplayCover(p);
            }
            else
            {
                throw new Exception("Cannot be added. It's not a category.");
            }
        }

        /// <summary>
        /// Create new category and add to this as children
        /// </summary>
        /// <returns>New category</returns>
        public DisplayCover AddCategory()
        {
            if (IsCategory)
            {
                var c = new Category(_source as Category);
                return new DisplayCover(c);
            }
            else
            {
                throw new Exception("Cannot be added. It's not a category.");
            }
        }

        /// <summary>
        /// Delete this from data tree
        /// </summary>
        public void Delete()
        {
            if (this.Parent != null)
            {
                this._source.Dispose();
                this.Parent.Children.Remove(this);

            }
            else
            {
                throw new Exception("cannot delete root category");
            }
        }

        /// <summary>
        /// Load all data tree
        /// </summary>
        /// <returns></returns>
        public static DisplayCover Load()
        {
            var storeRepository = new StoreRepository();
            var displayCover = new DisplayCover(storeRepository.Load());
            return displayCover;
        }

        /// <summary>
        /// Save all data tree
        /// </summary>
        public void Save()
        {
            var storeRepository = new StoreRepository();
            if (this.Source.GetType() == typeof(Category))
            {
                storeRepository.Save(this.Source as Category);
            }
        }

        #endregion //Methods

        #region Propertychanged

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged<T>(Expression<Func<T>> action)
        {
            var propertyName = GetPropertyName(action);
            OnPropertyChanged(propertyName);
        }

        private static string GetPropertyName<T>(Expression<Func<T>> action)
        {
            var expression = (MemberExpression)action.Body;
            var propertyName = expression.Member.Name;
            return propertyName;
        }

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        

        #endregion
    }
}
